#include "TcpConnection.h"
#include <unistd.h>
#include <iostream>
using std::cout; using std::endl;

static const int MIN_READ_BUFFER = 64;

TcpConnection::TcpConnection(int sockfd, InetAddress addr, Epoll &epoll)
:sockfd_(sockfd)
,peerAddr_(addr)
,epoll_(epoll)
,recvSize_(MIN_READ_BUFFER)
{
}

TcpConnection::~TcpConnection()
{
    shutdown();
}

void TcpConnection::shutdown()
{
    sockfd_.shutdownWrite();
}

void TcpConnection::readTcpData()
{
	string s(recvSize_, 0);
	int n = read(sockfd_.fd(), &s[0], recvSize_);
	if (n < 0)
	{
		switch(errno)
		{
		case EINTR:
		case EAGAIN:
			break;
		default:
            epoll_.channels_[sockfd_.fd()]->onCloseCb_();
			return;
		}
		return;
	}
	if (0 == n)
	{
        epoll_.channels_[sockfd_.fd()]->onCloseCb_();
		return;
	}

	if (n == recvSize_)
	{
		recvSize_ *= 2;
	}
	else if (recvSize_ > MIN_READ_BUFFER && n*2 < recvSize_)
	{
		recvSize_ /= 2;
	}

	data_.filterData(&s[0], n);
}
queue<string> &TcpConnection::getReadQueue()
{
	return data_.readQueue_.queue_;
}

void TcpConnection::sendTcpQueue()
{
    queue<string> &que = data_.writeQueue_;
    while(!que.empty())    
    {
        string &s = que.front();
        //cout << "sendTcpQueue  " << que.size() << "   " << *(uint16_t*)&s[0]<<s.substr(2) << endl;
        int sz = write(sockfd_.fd(), &s[0], s.size());
        if (sz < 0)
        {
            switch(errno)
            {
            case EINTR:
                continue;
            case EAGAIN:
                return;
            }
        }
        else if (sz < s.size())
        {
            s.erase(0, sz);
            return;
        }
        else if (sz == s.size())
        {
            que.pop();
        }
    }
    epoll_.epollWrite(sockfd_.fd(), this, false);
}

void TcpConnection::sendTcpData(string &s)
{
	uint16_t len = s.size();
	s.insert(0, (char*)&len, 2);
    if (data_.writeQueue_.empty())
    {
	    data_.writeQueue_.push(s);
        epoll_.epollWrite(sockfd_.fd(), this, true);
    }
    else
    {
        data_.writeQueue_.push(s);
    }
}

void TcpConnection::printConnInfo()
{
    cout << "socktype " << socktype_ << " events " << events << endl;
}
